﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Forms.Design;
using System.Windows.Input;
using System.Collections.Generic;

namespace Firefly.Controls {
    public class InputTextBox : ElementHost {
        #region Properties
        public List<string> History { get; private set; }
        public override System.Drawing.Color BackColor {
            get {
                return System.Drawing.Color.Black;
            }
            set {
                box.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black);
            }
        }
        public static System.Windows.Input.Key WinformsToWPFKey(System.Windows.Forms.Keys inputKey) {
            // Put special case logic here if there's a key you need but doesn't map...  
            try {
                return (System.Windows.Input.Key)Enum.Parse(typeof(System.Windows.Input.Key), inputKey.ToString());
            } catch {
                // There wasn't a direct mapping...    
                return System.Windows.Input.Key.None;
            }
        }
        public static System.Windows.Forms.Keys WPFtoWinformsKey(System.Windows.Input.Key inputKey) {
            try {
                return (System.Windows.Forms.Keys)Enum.Parse(typeof(System.Windows.Forms.Keys), inputKey.ToString());
            } catch {
                return System.Windows.Forms.Keys.None;
            }
        }
        [DefaultValue(false)]
        public bool Multiline {
            get { return box.AcceptsReturn; }
            set { box.AcceptsReturn = value; }
        }
        [DefaultValue(false)]
        public bool WordWrap {
            get { return box.TextWrapping != TextWrapping.NoWrap; }
            set { box.TextWrapping = value ? TextWrapping.Wrap : TextWrapping.NoWrap; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new System.Windows.UIElement Child {
            get { return base.Child; }
            set { /* Do nothing to solve a problem with the serializer !! */ }
        }
        public override string Text {
            get { return box.Text; }
            set { box.Text = value; }
        }
        public bool InputOK { get; set; } // Is it okay to send input events?
        #endregion

        public new event System.Windows.Forms.KeyEventHandler KeyDown;
        public event SendInputHandler SendInput;
        public delegate void SendInputHandler(object sender, string text);

        public InputTextBox() {
            this.box = new TextBox();
            this.History = new List<string>();
            base.Child = box;
            box.TextChanged += (s, e) => OnTextChanged(EventArgs.Empty);
            box.TextWrapping = System.Windows.TextWrapping.Wrap;
            box.SpellCheck.IsEnabled = true;
            box.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            this.Size = new System.Drawing.Size(100, 20);

            // Text
            box.FontFamily = new System.Windows.Media.FontFamily("Courier New");
            box.FontSize = 14.1f;
            box.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.White);

            // Events
            box.KeyDown += new System.Windows.Input.KeyEventHandler(box_KeyDown);
        }

        /// <summary>
        /// Handle keydown events and processing for shortcuts.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void box_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
            if (Keyboard.IsKeyDown(Key.LeftCtrl)) { // Is control key down?
                if (e.Key == System.Windows.Input.Key.Enter) {
                    e.Handled = true;
                    box.Text += '\n';
                    box.CaretIndex = box.Text.Length;
                } else if (e.Key == System.Windows.Input.Key.Up) {
                    e.Handled = true;
                    mHistoryIndex--;
                    RecallInputHistory(mHistoryIndex);
                } else if (e.Key == System.Windows.Input.Key.Down) {
                    e.Handled = true;
                    mHistoryIndex++;
                    RecallInputHistory(mHistoryIndex);
                }
            } else { // Control key is not down.
                if (e.Key == System.Windows.Input.Key.Enter && InputOK) {
                    // Send input event.
                    OnSendInput(box.Text);
                    mHistoryIndex = History.Count; // Reset history index.
                    e.Handled = true;
                }
            }
            // Not handled? Pass it.
            System.Windows.Forms.KeyEventArgs eventArgs = new System.Windows.Forms.KeyEventArgs(WPFtoWinformsKey(e.Key));
            if (KeyDown != null)
                KeyDown.Invoke(sender, eventArgs);
        }

        protected void OnSendInput(string s) {
            // Fire off the command event.
            if (SendInput != null)
                SendInput.Invoke(this, s);
            // Add a line to history.
            History.Add(s);
            // Clean up
            box.Clear();
        }

        /// <summary>
        /// Navigate the command history of the world.
        /// </summary>
        /// <param name="line"></param>
        public void RecallInputHistory(int line) {
            if (line != History.Count - 1 && box.Text != String.Empty
                && box.Text != History[History.Count]) { // If we're on the bottom most command
                // And the textbox isn't empty.
                // And the text in the textbox doesn't already exist in the buffer.
                // Save it.
                    History.Add(box.Text);
            }
            box.Text = History[line + 1];
        }

        public void Clear() {
            box.Clear();
        }

        private TextBox box;
        private int mHistoryIndex;
    }
}
